using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Net;
using System.Text.RegularExpressions;
using MiddlewareClient;
using System.Runtime.InteropServices; //interfaces - client server

namespace MiddlewareClient
{
    public class MiddlewareClient : IClient_cmd, IClient_rpt
    {
        IClient_rpt mClient;
        Socket.SocketClient mSocketClient;

        public MiddlewareClient(IClient_rpt a_client)
        {        
            mSocketClient = new Socket.SocketClient(ReadSocketData);
            mClient = a_client;
        }

        public void ReadSocketData(byte[] stream)
        {
            Console.WriteLine("[MC]::ReadSocketData");

            ShootResStruct structa = BytesToStruct(stream);
            Console.WriteLine("[MC]::ReadSocketData TYP:{0} CNTR:{1}", structa.header.msgType, structa.shootCnt);

            mClient.shootResult(structa.shootX, structa.shootY, structa.shootCnt);
        }

        private ShootResStruct BytesToStruct(byte[] dataIn)
        {
            GCHandle hDataIn = GCHandle.Alloc(dataIn, GCHandleType.Pinned);
            ShootResStruct ys = (ShootResStruct)Marshal.PtrToStructure(hDataIn.AddrOfPinnedObject(),
            typeof(ShootResStruct));
            hDataIn.Free();
            return ys;
        }

        ///////////////////////METHODS CALLED BY CLIENT//////////////////////////
        #region IClient_cmd Members

        public void connect(String a_ServerIP)
        {
            Console.WriteLine("[MC]::CONNECT from CLI SIP:{0}", a_ServerIP);

            //Get local ips
            IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());

            Regex regEx = new Regex("192.168.1.\\d{1,3}"); //TODO: ADDAPT
            //Find proper one like 10.28.1.4
            String foundIP = "";
            foreach(IPAddress ipAddress in localIPs)
            {
                Console.WriteLine("[MC]::CONNECT myIP::{0}", ipAddress.ToString());
                if (regEx.IsMatch(ipAddress.ToString()))
                {
                    foundIP = ipAddress.ToString();
                    break;
                }
            }

            //Send info to network layer
            Console.WriteLine("[MC]::CONNECT sending from {0}", foundIP);
            mSocketClient.Connect(a_ServerIP, 8000);

            //Pchanie do kostiego, musze znac ipka swojego i dac to w paramie
            mClient.connectResult(eReturnErrorCode.Success);
        }

        public void ready(DataTable a_dtShipsTable)
        {
            Console.WriteLine("[MC]::READY from CLI");
            //PRZEPYCHAM SHIPS W STREAMIE
        }

        public void shoot(uint a_uiXPos, uint a_uiYPos)
        {
            Console.WriteLine("[MC]::SHOOT from CLI X:{0},Y:{1}", a_uiXPos, a_uiYPos);

            ShootStruct shoot;
            shoot.header.msgType = 1; //SHOOT - TODO define enum!!!!!!
            shoot.header.msgLength = 16;// sizeof(ShootStruct) - sizeof(HeaderStruct); //ShootStruct - HeaderStruct sizeof
            shoot.shootX = a_uiXPos;
            shoot.shootY = a_uiYPos;
            byte[] sendPacket = Serialize(shoot);
            
            mSocketClient.Write(sendPacket); //buffer for testing
        }

        public void disconnect()
        {
            Console.WriteLine("[MC]::DISCONNECT from CLI");
            mSocketClient.Disconnect();
            //Notyfikuje dalej ze klient sie rozlaczyl
        }
        #endregion

        #region IClient_rpt Members

        public void readyResult(eReturnErrorCode a_eRetCode)
        {
            Console.WriteLine("[MC]::READY RESULT from CLI");
        }

        public void shootResult(uint a_uiXPos, uint a_uiYPos, uint a_uiShooted)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void disconnectResult(eReturnErrorCode a_eRetCode)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void connectResult(eReturnErrorCode a_eRetCode)
        {
            Console.WriteLine("[MC]::CONNECT RESULT");
            mClient.connectResult(a_eRetCode);
        }

        #endregion

        public static byte[] Serialize(object obj)
        {
            Type objectType = obj.GetType();
            int objectSize = Marshal.SizeOf(obj);
            IntPtr buffer = Marshal.AllocHGlobal(objectSize);
            Marshal.StructureToPtr(obj, buffer, false);
            byte[] array = new byte[objectSize];
            Marshal.Copy(buffer, array, 0, objectSize);
            Marshal.FreeHGlobal(buffer);
            return array;
        }
    }
}
